<template>
  <div class="tree-lists-wrapper">
    <el-checkbox v-if="isAllSelect" v-model="checkAll" @change="handleCheckAllChange">全选</el-checkbox>
    <el-tree ref="tree" :data="data" :node-key="nodeKey" :props="treeDefaultProps" :show-checkbox="showCheckbox" :empty-text="emptyText" :render-after-expand="renderAfterExpand"
             :highlight-current="highlightCurrent" :default-expand-all="defaultExpandAll" :expand-on-click-node="expandOnClickNode" :check-strictly="checkStrictly"
             :check-on-click-node="checkOnClickNode" :auto-expand-parent="autoExpandParent" :default-expanded-keys="treeDefaultExpanded" :default-checked-keys="treeDefaultChecked"
             :accordion="accordion" :indent="indent" :lazy="lazy" :load="loadNode" :draggable="draggable" :allow-drop="allowDrop" @node-click="handleNodeClick" @check-change="checkChange"
             @node-contextmenu="mouseRightClick" @check="checkClick" @node-drop="nodeDrop">
      <span class="custom-tree-node" slot-scope="{ node, data }" @mouseenter="treeOperationEnter('treeOperation'+ node.id)"
            @mouseleave="treeOperationLevel('treeOperation'+ node.id)">
        <span class="tree-icon-box">
          <i class="tree-icon" v-if="isIcon" :class="{'tree-icon-level1':node.level == 1,'tree-icon-level2': node.level == 2,'tree-icon-level3': node.level == 3}"></i>
          <!--<i class="tree-icon" :class="node.icon"></i>-->
          <span class="tree-label">{{ node.label }}</span>
        </span>
        <span class="tree-operation" :id="'treeOperation'+ node.id" style="display: none;">
          <el-button type="text" size="mini" @click.stop="() => addNode(node)" v-if="showFlag.isAddShow && operateLevel.add.indexOf(node.data.level) !== -1">
            <span class="add-operation"></span>
          </el-button>
          <el-button type="text" size="mini" @click.stop="() => editNode(node)" v-if="showFlag.isEditShow && operateLevel.edit.indexOf(node.data.level) !== -1">
            <span class="edit-operation"></span>
          </el-button>
          <el-button type="text" size="mini" @click.stop="() => deleteNode(node)" v-if="showFlag.isDeleteShow && operateLevel.delete.indexOf(node.data.level) !== -1">
            <span class="delete-operation"></span>
          </el-button>
        </span>
      </span>
    </el-tree>
  </div>
</template>
<script>
  export default {
    name: 'TreeView',
    components:{

    },
    props:{
      //tree数据
      treeData:Array,
      //....
      defaultProps:{
        type: Object,
        default: function () {
          return {}
        }
      },
      //每个树节点用来作为唯一标识的属性，整棵树应该是唯一的,默认是根据id
      nodeKey: {
        type: String,
        default: 'id'
      },
      //是否在文字前边显示图标
      isIcon: {
        type: Boolean,
        default: false
      },
      //判断哪一级显示那些操作
      operateLevel: {
        type: Object,
        default: function () {
          return {
            add: [1],
            edit: [1],
            delete: [1]
          }
        }
      },
      //决定显示那些操作
      showFlag: {
        type: Object,
        default: function () { //默认操作按钮显示
          return {
            isAddShow: false,
            isEditShow: false,
            isDeleteShow: false,
          }
        }
      },
      //数据为空时显示的文本
      emptyText:{
        type: String,
        default: '数据为空'
      },
      //是否在第一次展开某个树节点后才渲染其子节点
      renderAfterExpand:{
        type: Boolean,
        default: true
      },
      //是否高亮当前选中节点，默认值是 false
      highlightCurrent:{
        type: Boolean,
        default: false
      },
      //是否默认展开所有节点
      defaultExpandAll:{
        type: Boolean,
        default: false
      },
      //是否在点击节点的时候展开或者收缩节点， 默认值为 true，如果为 false，则只有点箭头图标的时候才会展开或者收缩节点
      expandOnClickNode:{
        type: Boolean,
        default: true
      },
      //是否在点击节点的时候选中节点，默认值为 false，即只有在点击复选框时才会选中节点
      checkOnClickNode:{
        type: Boolean,
        default: false
      },
      //展开子节点的时候是否自动展开父节点
      autoExpandParent:{
        type: Boolean,
        default: true
      },
      //默认展开的节点的 key 的数组
      treeDefaultExpandedKeys: Array,
      //节点是否可被选择,默认不显示
      showCheckbox:{
        type: Boolean,
        default: false
      },
      //在显示复选框的情况下，是否严格的遵循父子不互相关联的做法，false:是严格遵守，true:不遵守
      checkStrictly:{
        type: Boolean,
        default: false
      },
      //默认勾选的节点的 key 的数组
      treeDefaultCheckedKeys: Array,
      //是否每次只打开一个同级树节点展开
      accordion: {
        type: Boolean,
        default: false
      },
      //相邻级节点间的水平缩进，单位为像素，默认是16像素
      indent:{
        type: Number,
        default: 16
      },
      //是否懒加载子节点，需与 load 方法结合使用
      lazy: {
        type: Boolean,
        default: false
      },
      //是否开启拖拽节点功能
      draggable: {
        type: Boolean,
        default: false
      },
      //是否显示全选功能
      isAllSelect: {
        type: Boolean,
        default: false
      },
    },
    watch:{
      treeData:{
        handler: function (val) {
          val && (this.data = this.treeAddLevel(val,1));
        },
        immediate: true,
        deep: true
      },
      defaultProps:{
        handler: function (val) {
          val && (this.treeDefaultProps = val);
        },
        immediate: true,
        deep: true
      },
      //默认展开的节点的 key 的数组
      treeDefaultExpandedKeys:{
        handler: function (val) {
          val && (this.treeDefaultExpanded = val);
        },
        immediate: true,
        deep: true
      },
      //默认勾选的节点的 key 的数组
      treeDefaultCheckedKeys:{
        handler: function (val) {
          val && (this.treeDefaultChecked = val);
        },
        immediate: true,
        deep: true
      }
    },
    data(){
      return {
        data: [],
        treeDefaultProps: {
          children: 'children',
          label: 'label'
        },
        treeDefaultExpanded: [],//存放默认展开的节点
        treeDefaultChecked: [],//存放默认选中的节点
        checkAll:false
      }
    },
    mounted(){

    },
    methods:{
      //为tree data添加level字段
      treeAddLevel(data, level) {
        return data.map((d) => {
          let obj = this.cloneObj(d);
          obj.level = level;
          obj.children && (obj.children.length != 0) && (obj.children = this.treeAddLevel(obj.children, level + 1));
          return obj;
        })
      },
      //鼠标移入显示操作
      treeOperationEnter(id) {
        document.getElementById(id).style.display = "";
      },
      //鼠标移除隐藏操作
      treeOperationLevel(id) {
        document.getElementById(id).style.display = "none";
      },
      //添加节点
      addNode(node){
        // console.log("node",node);
        this.$emit('on-add', {
          node: node
        });
      },
      //编辑节点
      editNode(node){
        this.$emit('on-edit', {
          node: node
        });
      },
      //删除节点
      deleteNode(node){
        this.$emit('on-delete', {
          node: node
        });
      },
      //节点被点击时的回调,返回本节点信息
      handleNodeClick(data,node,self) {
        this.$emit('on-handle-click', {
          data: data,
          node: node,
          self: self
        });
      },
      //节点选中状态发生变化时的回调 data:本节点信息，isChecked:本节点选择状态，isNodeCheck:子节点是否有选中节点，checkedNodes:已选中的节点数组
      checkChange(data, isChecked,isNodeCheck){
        let checkedNodes = this.$refs.tree.getCheckedNodes();
        this.$emit('on-check-change', {
          data: data,
          isChecked: isChecked,
          isNodeCheck: isNodeCheck,
          checkedNodes: checkedNodes
        });
      },
      //当某一节点被鼠标右键点击时会触发该事件 mouseEvt:右键的位置信息，data：本节点的信息，node：也可以取到本节点信息，比data全些
      mouseRightClick(e,data,node,vueComponent){
        this.$emit('on-mouse-right-click', {
          mouseEvt: e,
          data: data,
          node: node,
          vueComponent: vueComponent,
        });
      },
      //当复选框被点击的时候触发
      checkClick(data,node){
        this.$emit('on-check-click', {
          data: data,
          node: node
        });
      },
      //判断节点能否被拖拽
      allowDrop(draggingNode, dropNode, type){
        //同级拖拽
        if (draggingNode.level === dropNode.level) {
          if (draggingNode.parent.id === dropNode.parent.id) {
            // 向上拖拽 || 向下拖拽
            return type === "prev" || type === "next";
          }
        } else {
          // 不同级进行处理
          return false;
        }
      },
      //拖拽成功完成时触发的事件
      /*共四个参数，依次为：被拖拽节点对应的 Node、结束拖拽时最后进入的节点、被拖拽节点的放置位置（before、after、inner）、event*/
      nodeDrop(draggingNode,dropNode,type,event){
        this.$emit('on-node-drop',{
          newData:this.data
        })
      },
      //懒加载方法
      loadNode(node, resolve){
        if (node.level === 0) {
          return resolve(this.data);
        }else{
          this.getChildrenNode(node.data.id,resolve)
        }
      },
      getChildrenNode(nodeId,resolve){
        this.$emit('get-children-node',nodeId,resolve);
      },
      //全选 返回所有选中的数据
      handleCheckAllChange(){
        if (this.checkAll) {
          this.$refs.tree.setCheckedNodes(this.data);
        } else {
          this.$refs.tree.setCheckedKeys([]);
        }
        let checkedNodes = this.$refs.tree.getCheckedNodes();
        this.$emit('on-checked-all',checkedNodes);
      }
    }
  }
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
  @import '../../../assets/styles/base_style';
  .tree-lists-wrapper {
    height: calc(100%);
    padding: 10px;
    overflow-y: auto;
    @include scrollbarStyle(5px, 5px, transparent, #dde5f0);
    .custom-tree-node {
      width: 100%;
      height: 100%;
      line-height: 33px;
      position: relative;
      .tree-operation {
        position: absolute;
        right: 50px;
        top: 0px;
        .add-operation {
          display: inline-block;
          background: url("../../../assets/images/treeview/add_icon.png") no-repeat;
          width: 18px;
          height: 18px;
          margin-right: 8px;
        }
        .edit-operation{
          display: inline-block;
          background: url("../../../assets/images/treeview/edit_icon.png") no-repeat;
          width: 18px;
          height: 18px;
          margin-right: 8px;
        }
        .delete-operation {
          display: inline-block;
          background: url("../../../assets/images/treeview/delete_icon.png") no-repeat;
          width: 20px;
          height: 20px;
        }
      }
    }
    .tree-icon-box {
      position: relative;
      .tree-icon {
        display: inline-block;
        padding: 0 2px;
        position: relative;
        top: 4px;
      }
      .tree-icon-level1 {
        background: url("../../../assets/images/treeview/icon_level1.png") no-repeat;
        width: 24px;
        height: 18px;
      }
      .tree-icon-level2 {
        background: url("../../../assets/images/treeview/icon_level2.png") no-repeat;
        width: 22px;
        height: 16px;
      }
      .tree-icon-level3 {
        background: url("../../../assets/images/treeview/icon_level2.png") no-repeat;
        width: 22px;
        height: 16px;
      }
    }
  }
</style>
<style rel="stylesheet/scss" lang="scss">
  @import "../../../assets/styles/base_style";
  .tree-lists-wrapper {
    .el-tree{
      background: transparent;
    }
    .el-tree-node__content {
      height: 36px;
    }
    .el-checkbox__inner {
      width: 17px;
      height: 17px;
    }
    .el-tree-node__expand-icon {
      font-size: 20px;
    }
    .el-checkbox__inner::after {
      webkit-box-sizing: content-box;
      box-sizing: content-box;
      content: "";
      border: 2px solid #fff;
      border-left: 0;
      border-top: 0;
      height: 7px;
      left: 5px;
      position: absolute;
      top: 2px;
      -webkit-transform: rotate(45deg) scaleY(0);
      transform: rotate(45deg) scaleY(0);
      width: 3px;
      -webkit-transition: -webkit-transform 0.15s ease-in 0.05s;
      transition: -webkit-transform 0.15s ease-in 0.05s;
      transition: transform 0.15s ease-in 0.05s, -webkit-transform 0.15s ease-in 0.05s;
      -webkit-transform-origin: center;
      transform-origin: center;
    }
    .el-checkbox__input.is-indeterminate .el-checkbox__inner::before {
      content: "";
      position: absolute;
      display: block;
      background-color: #fff;
      height: 2px;
      -webkit-transform: scale(0.5);
      transform: scale(0.5);
      left: 0;
      right: 0;
      top: 7px;
    }
    .el-checkbox__label{
      font-size: 16px;
    }
  }
</style>
